package gappengko;

import java.io.BufferedReader;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.Hashtable;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

 /** Various operations to transform a HttpServletRequest object into operations
  * for SimpleDatastore
 */
public class HttpRequestHandler {

	private final JsonSimpleDatastore _sds = new JsonSimpleDatastore(System.getProperty("gappengko.kind"));

	/** returns the json representation of the entity with key equals 
	 * to the parameter GET/POST _key 
	 */
  public String getJson(HttpServletRequest req) throws Exception {
    return _sds.getJSON(req.getParameter(Constants.KEY)).toString();    
  }
	
  /** Transforms the raw request.getParameterMap() into a usable Map<String,String> */
  static Map<String,String> getDataAsMap(HttpServletRequest request) {
    JsonObject json = (JsonObject) getDataAsJson(request);   
    Map<String, String> m = new Hashtable<String, String>() ;
    for (Entry<String, JsonElement> el : json.entrySet()) {
      m.put(el.getKey(), el.getValue().getAsString());
    }
    return m;    
  }
  
  /** Transforms the raw request.getParameterMap() into a JsonArray */
  private static JsonElement getDataAsJson(HttpServletRequest request) {
    try {

    if (request.getContentType() == null /* for Flash-based requests*/ || request.getContentType().contains("application/x-www-form-urlencoded") || request.getContentType().contains("application/jsonp")) {
      String data = request.getParameter("data"); //either get or post
      return  new JsonParser().parse(data);
    }

    if (request.getContentType().contains("application/json")) {
      String data = null;
      if ("GET".equals(request.getMethod())) {
        data = URLDecoder.decode(request.getQueryString());        
      } else {
        data = getPostData(request);
      }
      return  new JsonParser().parse(data);
    }
    } catch (IOException e) {
      throw new JSKommentException(e);
    } 
    
    throw new JSKommentException("not a valid request");
    
    
    
  }

  /** removes spurious node from request data (e.g. Recaptcha data) */
  public void cleanRequestData(Map<String, String> map) {
    map.remove(Constants.CALLBACK);
    map.remove("_");
    map.remove(RecaptchaUtils.RECAPTCHA_CHALLENGE_FIELD);
    map.remove(RecaptchaUtils.RECAPTCHA_RESPONSE_FIELD);
  }  
  
  /** Creates a new entity based on the information present in the request */
	public String createEntityFromRequest(HttpServletRequest req) throws Exception {
    Map<String, String> m = getDataAsMap(req);	  
    cleanRequestData(m);
		return _sds.createEntity(m).get(Constants.KEY).getAsString();
	}
	

	/** Gets a list of JSONObject bas on the parameters in the request */
	public JsonArray search(HttpServletRequest req) throws Exception {
    Map<String, String> m = getDataAsMap(req);
    cleanRequestData(m);
		return _sds.search(m);
	}

	
	 /** Gets a list of lists of JSONObject based on the parameters in the request */
  public JsonArray multipleSearch(HttpServletRequest req) throws Exception {
    return multipleSearch((JsonArray)getDataAsJson(req));
  }

  /** Reads the post data in a String */
  public static String getPostData(HttpServletRequest req) throws IOException {
    
    // post data can be read only once, so we cache the result
    if (req.getAttribute("post_data")!=null) {
      return (String) req.getAttribute("post_data");
    }
    
    // getting the post data
    BufferedReader reader = req.getReader();
    StringBuilder sb = new StringBuilder();
    String line = reader.readLine();
    while (line != null) {
        sb.append(line + "\n");
        line = reader.readLine();
    }
    reader.close();
    String postData = sb.toString();
    req.setAttribute("post_data", postData);
    return postData;
  }

  /** Gets a list of lists of JSONObject based on the parameters in the request */
  public JsonArray multipleSearch(JsonArray array) throws Exception {    
    JsonArray result = new JsonArray();
    
    // for each object in the list
    for (JsonElement elem : array) {
      result.add(_sds.search(elem.getAsJsonObject()));
    }
    
    return result;
  }

}
